Zbudujmy model Random Forest oparty o dane FICO, dotyczące ryzyka że kredytobiorca będzie spóźniał się się z płatnościami ratalnymi.
import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.impute import SimpleImputer
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import train_test_split, cross_val_score, RandomizedSearchCV
from xgboost import *
def get_data():
read = pd.read_csv("heloc_dataset_v1.csv")
data_columns = [f for f in read.columns if f != 'RiskPerformance']
grouped = read.groupby(data_columns)
filtered = grouped.filter(lambda x: True)
filtered = filtered.sample(frac=1).reset_index(drop=True)
return filtered['RiskPerformance'], filtered[data_columns]
def prep_data():
res, data = get_data()
res = [1 if t == "Good" else 0 for t in res]
for c in data.columns:
data[c] = [-9 if t == -7 or t == -8 or t == -9 else t for t in data[c]]
orig_data = data
#data = imp.fit_transform(data)
return orig_data, np.array(res), data
def get_model():
return RandomForestClassifier(100, max_samples=800, n_jobs=-1, max_features=5)
Podzielmy zbiór na trenignowy i testowy
orig, res, data = prep_data()
Xtrain, Xtest, Ytrain, Ytest = train_test_split(data, res, train_size=0.8)
model = get_model()
model.fit(Xtrain, Ytrain)
Zbadajmy poprawność tego modelu. Z AUC w okolicach 0.8 jest on wystarczający dla naszych potrzeb
def avg(model, x, y, eq):
pred = model.predict(x)
acc = [1 if eq(e,s) else 0 for (e,s) in zip(pred, y)]
return np.average(acc)
print("Avg: " + str(avg(model, Xtest, Ytest, lambda x, y: int(round(x)) == y)))
print("Avg on train: " + str(avg(model, Xtrain, Ytrain, lambda x, y: int(round(x)) == y)))
roc_auc = roc_auc_score(Ytest, model.predict_proba(Xtest)[:, 1])
print("Roc auc: " + str(roc_auc))
Następnie zbudujmy explainer Lime dla danych tabelarycznych, i przedstawmy wyniki wyjaśniania dla losowych instancji testowych.
import lime
import lime.lime_tabular
explainer = lime.lime_tabular.LimeTabularExplainer(np.array(Xtrain), feature_names=orig.columns, verbose=True)
def wrap_predict(model, data_x):
ndata = pd.DataFrame(data_x, columns=orig.columns)
return model.predict_proba(ndata)
il = [25,658,165]
for i in il:
print("-----------------------")
print("Expected: " + str(Ytest[i]))
exp = explainer.explain_instance(Xtest.iloc[i], lambda d: wrap_predict(model, d), num_features=4)
exp.show_in_notebook(show_table=True)
for e in exp.as_list():
print(e)
Jak widać z powyższych danych najważniejsze atrybuty wskazane przez lime są dosyć konsekwentne. Widoczny jest duży wpływ zmiennej ExternalRiskEstimate, rezprezentująca zewnętrzny scoring, która w dwóch z powyższych wyjaśnień oddziałuje z największą siłą na wynik, a w trzecim przykładzie choć na czwartej pozycji, to i tak wpływa z wartością równą 70% wpływu najistotniejszej zmiennej dla tej obserwacji. We wszystkich trzech wynikach widoczna jest także zmienna PercentTradesNeverDelq mówiąca o temrinowości kredytobiorcy. Wszystko to zgadza się również z poprzednimi obserwacjami dotyczącymi tego zbioru, w tym również z wynikami analizy metodą SHAP, przedstawionymi w poprzedniej pracy.
xgb = XGBClassifier(verbose=0, subsample=0.8)
xgb.missing = -9
xgb.n_estimators = 25
xgb.max_depth = 8
xgb.fit(Xtrain, Ytrain)
print("Avg: " + str(avg(xgb, Xtest, Ytest, lambda x, y: int(round(x)) == y)))
print("Avg on train: " + str(avg(xgb, Xtrain, Ytrain, lambda x, y: int(round(x)) == y)))
roc_auc = roc_auc_score(Ytest, xgb.predict_proba(Xtest)[:, 1])
print("Roc auc: " + str(roc_auc))
Spójrzmy na porównanie z drugim modelem, stworzonym XGBoostem.
for i in [1697]:
print("-----------------------")
print("Expected: " + str(Ytest[i]))
exp_rf = explainer.explain_instance(Xtest.iloc[i], lambda d: wrap_predict(model, d), num_features=4)
exp_rf.show_in_notebook(show_table=True)
exp = explainer.explain_instance(Xtest.iloc[i], lambda d: wrap_predict(xgb, d), num_features=4)
exp.show_in_notebook(show_table=True)
Spójrzmy na powyższe wyjasnienia obu modeli dla pewnej instancji. Modele zwróciły różne wyniki dla tej obserwacji, i jak widać z powyższych tabelek, trzy z czterech zmiennych uznanych za najważniejsze dla ich wyniku są różne. Co ciekawe dla tej obserwacji wspólna zmienna, ExternalRiskEstimate, wpływa z podobną wagą na wynik obu modeli.